package com.mm.cloud.lease.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mm.cloud.common.core.enums.DeleteEnum;
import com.mm.cloud.common.core.enums.RoomEarnestEnum;
import com.mm.cloud.common.core.enums.RoomLeaseEnum;
import com.mm.cloud.common.core.exception.BaseException;
import com.mm.cloud.common.core.result.Result;
import com.mm.cloud.common.core.result.ResultConstants;
import com.mm.cloud.common.core.result.ResultUtil;
import com.mm.cloud.common.redis.annotation.DistributionLock;
import com.mm.cloud.common.security.helper.LoginUserHelper;
import com.mm.cloud.common.security.loginuser.LoginUser;
import com.mm.cloud.lease.dto.room.form.BatchSaveRoomDTO;
import com.mm.cloud.lease.dto.room.form.DeleteRoomDTO;
import com.mm.cloud.lease.dto.room.form.SaveRoomDTO;
import com.mm.cloud.lease.dto.room.form.UpdateRoomDTO;
import com.mm.cloud.lease.dto.room.query.QueryRoomDTO;
import com.mm.cloud.lease.entity.Room;
import com.mm.cloud.lease.mapper.RoomMapper;
import com.mm.cloud.lease.service.IRoomService;
import com.mm.cloud.lease.service.impl.convert.room.RoomConvert;
import com.mm.cloud.lease.vo.room.RoomPageVO;
import com.mm.cloud.lease.vo.room.RoomVO;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 房间 服务实现类
 * </p>
 *
 * @author mr
 * @since 2025-07-01
 */
@Service
public class RoomServiceImpl extends ServiceImpl<RoomMapper, Room> implements IRoomService {

    @Override
    public Result<Long> saveRoom(SaveRoomDTO dto) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        
        // 检查门牌号是否已被使用
        Room room = RoomConvert.convert(dto);
        room.setCompanyId(loginUser.getCompanyId());
        checkRoomDoorNumber(loginUser.getCompanyId(), dto.getHousingId(), List.of(room));
        
        // 新增房间
        room.setCreaterId(loginUser.getUserId());
        room.setIsLease(RoomLeaseEnum.NOT_LEASE.getStatus());
        room.setIsEarnest(RoomEarnestEnum.NOT_EARNEST.getStatus());
        this.save(room);
        return ResultUtil.success(room.getId());
    }

    @Override
    public Result<String> updateRoom(UpdateRoomDTO dto) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        
        // 检查房间是否存在
        getAssertRoom(loginUser.getCompanyId(), dto.getId());
        
        // 检查门牌号是否已被其他房间使用
        Room room = RoomConvert.convert(dto);
        room.setCompanyId(loginUser.getCompanyId());
        checkRoomDoorNumberForUpdate(loginUser.getCompanyId(), dto.getHousingId(), dto.getId(), List.of(room));
        
        // 修改房间
        room.setUpdaterId(loginUser.getUserId());
        this.updateById(room);
        return ResultUtil.success();
    }

    @Override
    @DistributionLock(key = "HOUSING:DELETE", paramName = "#dto.id", isReturn = true)
    public Result<String> deleteRoom(DeleteRoomDTO dto) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        // 查询房间信息
        Room room = this.getRoom(loginUser.getCompanyId(), dto.getId());

        // 房间已是回收站删除状态
        if (DeleteEnum.RECYCLE_DELETE.getStatus().equals(room.getIsDelete()) && DeleteEnum.RECYCLE_DELETE.getStatus().equals(dto.getIsDelete())) {
            return ResultUtil.fail("数据已删除");
        }

        // 房间已是永久删除状态
        if (DeleteEnum.DELETE.getStatus().equals(room.getIsDelete()) && DeleteEnum.RECYCLE_DELETE.getStatus().equals(dto.getIsDelete())) {
            return ResultUtil.fail("数据已删除");
        }

        // 房间已是永久删除状态
        if (DeleteEnum.DELETE.getStatus().equals(room.getIsDelete()) && DeleteEnum.DELETE.getStatus().equals(dto.getIsDelete())) {
            return ResultUtil.fail("数据已删除");
        }

        // 删除房间
        Room updateRoom = new Room();
        updateRoom.setId(dto.getId());
        updateRoom.setIsDelete(dto.getIsDelete());
        updateRoom.setUpdaterId(loginUser.getUserId());
        this.updateById(updateRoom);
        return ResultUtil.success();
    }

    @Override
    @Transactional
    public Result<String> batchSaveRoom(BatchSaveRoomDTO dto) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        
        // 检查门牌号是否已被使用
        List<Room> roomList = dto.getRoomList().stream().map(e -> {
            Room room = RoomConvert.convert(e);
            room.setCompanyId(loginUser.getCompanyId());
            return room;
        }).collect(Collectors.toList());
        
        // 检查所有房间的门牌号唯一性
        if (CollectionUtil.isNotEmpty(roomList)) {
            Long housingId = roomList.get(0).getHousingId();
            checkRoomDoorNumber(loginUser.getCompanyId(), housingId, roomList);
        }
        
        // 新增房间
        roomList.forEach(room -> {
            room.setCreaterId(loginUser.getUserId());
            room.setIsLease(RoomLeaseEnum.NOT_LEASE.getStatus());
            room.setIsEarnest(RoomEarnestEnum.NOT_EARNEST.getStatus());
        });
        this.saveBatch(roomList);
        return ResultUtil.success();
    }

    @Override
    public Result<RoomVO> getRoom(Long id) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        Room room = getAssertRoom(loginUser.getCompanyId(), id);
        RoomVO roomVO = RoomConvert.convertToVO(room);
        return ResultUtil.success(roomVO);
    }

    @Override
    public Result<List<RoomPageVO>> getRoomList(QueryRoomDTO dto) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        dto.setCompanyId(loginUser.getCompanyId());
        IPage<RoomPageVO> page = this.baseMapper.getRoomList(new Page<>(dto.getPage(), dto.getLimit()), dto);
        return ResultUtil.success(page.getRecords(), page.getTotal());
    }

    @Override
    public Result<String> checkRoomRentable(Long id) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        Room room = this.getOne(Wrappers.<Room>lambdaQuery()
                .eq(Room::getId, id)
                .eq(Room::getCompanyId, loginUser.getCompanyId()));
        if (room == null || !DeleteEnum.NOT_DELETE.getStatus().equals(room.getIsDelete())) {
            return ResultUtil.fail(ResultConstants.QUERY_NOT_FOUND_DATA);
        }
        if (!RoomLeaseEnum.NOT_LEASE.getStatus().equals(room.getIsLease())) {
            return ResultUtil.fail("房间已租，无法登记租客");
        }
        return ResultUtil.success();
    }

    /**
     * 获取房间
     *
     * @param companyId 公司id
     * @param id        id
     * @return Room
     */
    private Room getAssertRoom(Long companyId, Long id) {
        Room room = this.getRoom(companyId, id);
        if (!DeleteEnum.NOT_DELETE.getStatus().equals(room.getIsDelete())) {
            throw new BaseException(ResultConstants.QUERY_NOT_FOUND_DATA);
        }
        return room;
    }

    /**
     * 获取房间
     *
     * @param companyId 公司id
     * @param id        id
     * @return Room
     */
    private Room getRoom(Long companyId, Long id) {
        Assert.notNull(companyId, "companyId is null");
        Assert.notNull(id, "id is null");
        Room room = this.getOne(Wrappers.<Room>lambdaQuery()
                .eq(Room::getId, id)
                .eq(Room::getCompanyId, companyId));
        if (Objects.isNull(room)) {
            throw new BaseException(ResultConstants.QUERY_NOT_FOUND_DATA);
        }
        return room;
    }

    private void checkRoomDoorNumber(Long companyId, Long housingId, List<Room> roomList) {
        List<String> doorNumberList = roomList.stream().map(Room::getDoorNumber).distinct().toList();
        List<Room> dbRoomList = this.baseMapper.selectList(Wrappers.<Room>lambdaQuery()
                .eq(Room::getCompanyId, companyId)
                .eq(Room::getHousingId, housingId)
                .ne(Room::getIsDelete, DeleteEnum.DELETE.getStatus())
                .in(Room::getDoorNumber, doorNumberList));
        if (CollectionUtil.isEmpty(dbRoomList)) {
            return;
        }
        // 获取数据库中已存在的房间
        Map<String, Room> dbRoomMap = dbRoomList.stream().collect(Collectors.toMap(e -> e.getDoorNumber() + "-" + (Objects.nonNull(e.getFloor()) ? e.getFloor() : Strings.EMPTY), Function.identity()));
        for (Room room : roomList) {
            String key = room.getDoorNumber() + "-" + (Objects.nonNull(room.getFloor()) ? room.getFloor() : Strings.EMPTY);
            if (dbRoomMap.containsKey(key)) {
                throw new BaseException("门牌号已被使用");
            }
        }
    }

    /**
     * 检查房间门牌号是否已被使用（更新时使用，排除当前房间）
     *
     * @param companyId 公司id
     * @param housingId 房源id
     * @param excludeRoomId 排除的房间id
     * @param roomList 房间列表
     */
    private void checkRoomDoorNumberForUpdate(Long companyId, Long housingId, Long excludeRoomId, List<Room> roomList) {
        List<String> doorNumberList = roomList.stream().map(Room::getDoorNumber).distinct().toList();
        List<Room> dbRoomList = this.baseMapper.selectList(Wrappers.<Room>lambdaQuery()
                .eq(Room::getCompanyId, companyId)
                .eq(Room::getHousingId, housingId)
                .ne(Room::getId, excludeRoomId)
                .ne(Room::getIsDelete, DeleteEnum.DELETE.getStatus())
                .in(Room::getDoorNumber, doorNumberList));
        if (CollectionUtil.isEmpty(dbRoomList)) {
            return;
        }
        // 获取数据库中已存在的房间
        Map<String, Room> dbRoomMap = dbRoomList.stream().collect(Collectors.toMap(e -> e.getDoorNumber() + "-" + (Objects.nonNull(e.getFloor()) ? e.getFloor() : Strings.EMPTY), Function.identity()));
        for (Room room : roomList) {
            String key = room.getDoorNumber() + "-" + (Objects.nonNull(room.getFloor()) ? room.getFloor() : Strings.EMPTY);
            if (dbRoomMap.containsKey(key)) {
                throw new BaseException("门牌号已被使用");
            }
        }
    }
}
